﻿using System;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;

namespace Inovout.Descriptors
{
    public class ClassDescriptor : MemberDescriptor, ITypeDescriptor
    {
        #region Constructor

        /// <summary>
        /// 初始化 EnumDictionary类的新实例。
        /// </summary>
        /// <param name="enumType">枚举声明类型</param>
        public ClassDescriptor(Type classType)
            : base(classType)
        {
            ArgumentGuard.IsClassType(classType, "classType");

            ConstructorInfo[] constructorInfos = classType.GetConstructors();
            constructors = new ConstructorDescriptor[constructorInfos.Length];
            for (int i = 0; i < constructors.Length; i++)
            {
                constructors[i] = new ConstructorDescriptor(constructorInfos[i]);
            }

            PropertyInfo[] propertyInfos = classType.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
            properties = new PropertyDescriptor[propertyInfos.Length];
            for (int i = 0; i < properties.Length; i++)
            {
                properties[i] = new PropertyDescriptor(propertyInfos[i]);
            }

            Type declaringType = classType;

            List<FieldDescriptor> fieldList = new List<FieldDescriptor>();
            while (!declaringType.Equals(typeof(Object)))
            {
                FieldInfo[] fieldInfos = declaringType.GetFields(BindingFlags.Public | BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static);
                foreach (FieldInfo fieldInfo in fieldInfos)
                {
                    fieldList.Add(new FieldDescriptor(fieldInfo));
                }
                declaringType = declaringType.BaseType;
            }
            fields = fieldList.ToArray();
        }


        #endregion    

        private readonly FieldDescriptor[] fields;
        public FieldDescriptor[] Fields
        {
            get { return fields; }
        }

        public PropertyDescriptor GetProperty(string propertyName)
        {
            return properties.Single(property=>property.Name.Equals(propertyName));
        }


        private readonly PropertyDescriptor[] properties;
        public PropertyDescriptor[] Properties
        {
            get { return properties; }
        }

        private readonly ConstructorDescriptor[] constructors;
        public ConstructorDescriptor[] Constructors
        {
            get { return constructors; }
        }

        public static ClassDescriptor Create(Type type)
        {
            return new ClassDescriptor(type);
        }

        public FieldDescriptor GetField(string fieldName)
        {
            return fields.SingleOrDefault(field => field.Name.Equals(fieldName));
        }

        public bool HasProperty(string propertyName)
        {
            return GetProperty(propertyName) != null;
        }

        public bool HasField(string fieldName)
        {
            return GetField(fieldName) != null;
        }

        public  Dictionary<string, object> GetPropertyValues(object instance)
        {
            return properties.ToDictionary(property => property.Name, property => property.GetValue(instance));
        }
        public void SetPropertyValues(object instance,Dictionary<string, object> propertyValues)
        {
            foreach (PropertyDescriptor propertyDesciptor in properties.Where(property => !property.IsReadOnly))
            {
                object value;
                if (propertyValues.TryGetValue(propertyDesciptor.Name, out value))
                {
                    propertyDesciptor.SetValue(instance, value);
                }
            }

        }
 
    }
}
